package org.xxpay.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.xxpay.core.entity.*;
import org.xxpay.core.service.IPayInterfaceService;
import org.xxpay.service.dao.mapper.PayInterfaceMapper;

import java.lang.reflect.Field;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.json.JSONObject;
/**
 * @author: dingzhiwei
 * @date: 2018/5/3
 * @description: 支付接口
 */
@Slf4j
@Service(interfaceName = "org.xxpay.core.service.IPayInterfaceService", version = "1.0.0", retries = -1)
public class PayInterfaceServiceImpl implements IPayInterfaceService {

    @Autowired
    private PayInterfaceMapper payInterfaceMapper;

    @Override
    public int add(PayInterface payInterface) {
        return payInterfaceMapper.insertSelective(payInterface);
    }

    @Override
    public int update(PayInterface payInterface) {
        return payInterfaceMapper.updateByPrimaryKeySelective(payInterface);
    }

    @Override
    public PayInterface findByCode(String ifCode) {
        return payInterfaceMapper.selectByPrimaryKey(ifCode);
    }

    @Override
    public List<PayInterface> select(int offset, int limit, PayInterface payInterface) {
        PayInterfaceExample example = new PayInterfaceExample();
        example.setOrderByClause("createTime DESC");
        example.setOffset(offset);
        example.setLimit(limit);
        PayInterfaceExample.Criteria criteria = example.createCriteria();
        setCriteria(criteria, payInterface);
        return payInterfaceMapper.selectByExample(example);
    }

    @Override
    public Integer count(PayInterface payInterface) {
        PayInterfaceExample example = new PayInterfaceExample();
        PayInterfaceExample.Criteria criteria = example.createCriteria();
        setCriteria(criteria, payInterface);
        return payInterfaceMapper.countByExample(example);
    }

    @Override
    public List<PayInterface> selectAll(PayInterface payInterface) {
        PayInterfaceExample example = new PayInterfaceExample();
        example.setOrderByClause("createTime DESC");
        PayInterfaceExample.Criteria criteria = example.createCriteria();
        setCriteria(criteria, payInterface);
        return payInterfaceMapper.selectByExample(example);
    }

    @Override
    public int delete(PayInterface payInterface) {
        return payInterfaceMapper.deleteByPrimaryKey(payInterface.getIfCode());
    }

    @Override
    public List<PayInterface> selectAllByTypeCode(String ifTypeCode) {
        PayInterface payInterface = new PayInterface();
        payInterface.setIfTypeCode(ifTypeCode);
        return selectAll(payInterface);
    }

    /**
     * 这只是简单的创建了一个单子,但是还未支付成功所以不会保存到数据库
     *
     * @param payInterface
     * @param amount
     * @param MchId
     * @return
     */
    @Override
    public PayOrder payInterface2Order(PayInterface payInterface, Long amount, Long MchId) {
        final PayOrder payOrder = new PayOrder();
        payOrder.setAmount(amount);
        payOrder.setChannelId(payInterface.getIfCode());
        payOrder.setPayOrderId(payInterface.getIfCode() + System.currentTimeMillis());
        payOrder.setMchOrderNo(payInterface.getIfCode() + System.currentTimeMillis());
        payOrder.setMchId(MchId);
        payOrder.setStatus((byte) 0);//还未支付
        payOrder.setChannelId(payInterface.getIfCode());
        //下面的这俩个要根据具体的业务逻辑修改,现在先填上
        payOrder.setSubject("支付接口"+payInterface.getIfCode());
        payOrder.setBody(payInterface.getPayType());
        //回调地址
        payOrder.setNotifyUrl("54.92.115.79");
        return payOrder;
    }
///所有参数参与加密
//    @Override
//    public String generateSignature(PayOrder payOrder,String privatekey) {
//        // 创建一个 TreeMap 对象，用于对参数按照键名进行排序
//        TreeMap<String, String> sortedParams = new TreeMap<>();
//        // 获取 PayInterfaceType 类中的所有字段
//        Field[] fields = PayOrder.class.getDeclaredFields();
//        for (Field field : fields) {
//            field.setAccessible(true); // 设置访问权限
//            try {
//                Object value = field.get(payOrder);
//
//                // 如果参数值为空，则跳过该参数
//                if (value != null && !String.valueOf(value).isEmpty()) {
//                    sortedParams.put(field.getName(), String.valueOf(value));
//                }
//            } catch (IllegalAccessException e) {
//                e.printStackTrace();
//            }
//        }
//        // 创建一个 StringBuilder 对象，用于拼接参数字符串
//        StringBuilder sb = new StringBuilder();
//        for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
//            String key = entry.getKey();
//            String value = entry.getValue();
//
//            // 拼接参数名和参数值
//            sb.append(key).append("=").append(value).append("&");
//        }
//        if (sb.length() > 0) {
//            //sb.deleteCharAt(sb.length() - 1);//删除最后一个多余的 "&" 符号
//            //key要参与加密
//            StringBuilder  original= new StringBuilder(sb);
//            sb.append(privatekey);
//
//            //加密
//            String signature = sb.toString();
//            try {
//                MessageDigest md = MessageDigest.getInstance("MD5");
//                byte[] messageDigest = md.digest(signature.getBytes());
//                StringBuilder hexString = new StringBuilder();
//                for (byte b : messageDigest) {
//                    String hex = Integer.toHexString(0xFF & b);
//                    if (hex.length() == 1) {
//                        hexString.append('0');
//                    }
//                    hexString.append(hex);
//                }
//                //如果要使用的是最终请求结果就使用下面两个的返回值,就是多了除了签名之外的其他信息
////                original.append(hexString);
////                return original.toString();
//                return hexString.toString(); //直接返回签名
//            } catch (NoSuchAlgorithmException e) {
//                e.printStackTrace();
//                return "";
//            }
//        }
//        return "";
//    }
    //只是需要的参数参与加密
    @Override
    public String generateSign(PayOrder payOrder,String privatekey) {
        // 创建一个 TreeMap 对象，用于对参数按照键名进行排序
        TreeMap<String, String> sortedParams = new TreeMap<>();
        // 获取 PayInterfaceType 类中的所有字段
        Field[] fields = PayOrder.class.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true); // 设置访问权限
            try {
                Object value = field.get(payOrder);

                // 如果参数值为空或者不需要参与签名，则跳过该参数
                if (value == null || String.valueOf(value).isEmpty()
                        /*|| !isParamNeedSign(field.getName())*/) {
                    continue;
                }

                sortedParams.put(field.getName(), String.valueOf(value));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        // 创建一个 StringBuilder 对象，用于拼接参数字符串
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();

            // 拼接参数名和参数值
            sb.append(key).append("=").append(value).append("&");
        }
        if (sb.length() > 0) {
            //key要参与加密
            StringBuilder original = new StringBuilder(sb);
            original.append("key=");
            original.append(privatekey);

            //加密
            String signature = original.toString();
            log.info("加密前的参数：{}", signature);
            try {
                MessageDigest md = MessageDigest.getInstance("MD5");
                byte[] messageDigest = md.digest(signature.getBytes());
                StringBuilder hexString = new StringBuilder();
                for (byte b : messageDigest) {
                    String hex = Integer.toHexString(0xFF & b);
                    if (hex.length() == 1) {
                        hexString.append('0');
                    }
                    hexString.append(hex);
                }

                return hexString.toString(); //直接返回签名
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
                return "";
            }
        }
        return "";
    }

    @Override
    public Integer findByName(String codeName) {
        String pattern = "\\[(\\d+)]"; // 正则表达式匹配中括号内的数字

        // 创建 Pattern 对象
        Pattern r = Pattern.compile(pattern);

        // 创建 Matcher 对象
        Matcher m = r.matcher(codeName);
        if (m.find( )) {
            System.out.println("找到匹配的内容： " + m.group(1)); // 获取匹配的数字
            return Integer.parseInt(m.group(1)); // 返回匹配的数字
        } else {
            return null;
        }
    }

    /**
     * 需要参与加密的字段名称
     * @param paramName
     * @return
     */
    private boolean isParamNeedSign(String paramName) {
        switch (paramName) {
            case "mchId":
            case "productId":
            case "mchOrderNo":
            case "amount":
            case "notifyUrl":
            case "returnUrl":
            case "channelId":
                return true;
            default:
                return false;
        }
    }

    @Override
    public String sendToPay(PayOrder payOrder, String signature, String ifTypeReqUrl) {
        // 创建一个 HttpClient 对象
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 创建一个HttpPost对象
        //HttpPost httpPost = new HttpPost("http://pay.saibinli.xyz/api/pay/create_order");
        //HttpPost httpPost = new HttpPost("http://localhost:3020/api/pay/create_order");
        //HttpPost httpPost = new HttpPost("http://156.224.23.121:3020/api/pay/create_order");
        HttpPost httpPost = new HttpPost(ifTypeReqUrl);//请求的支付网关


        // 创建参数列表
        List<NameValuePair> params = new ArrayList<>();

        // 获取 payOrder 对象的所有非空字段
        Field[] fields = payOrder.getClass().getDeclaredFields();

        for (Field field : fields) {
            field.setAccessible(true);
            Object value = null;
            try {
                value = field.get(payOrder);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
            if (value != null) {
                params.add(new BasicNameValuePair(field.getName(), value.toString()));
            }
        }
        params.add(new BasicNameValuePair("sign", signature));

        // 创建表单实体
        UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, Consts.UTF_8);
        httpPost.setEntity(entity);

        // 发送请求并处理响应
        try {
            // 发送请求并处理响应
            CloseableHttpResponse response = httpClient.execute(httpPost);

            try {
                // 获取响应状态码
                int statusCode = response.getStatusLine().getStatusCode();

                // 解析响应实体
                HttpEntity responseEntity = response.getEntity();
                String responseBody = EntityUtils.toString(responseEntity, "UTF-8");

                // 处理状态码和信息
                if (statusCode == 200) {
                    // HTTP 请求成功
                    if (responseBody.contains("\"retCode\":\"SUCCESS\"")) {
                        // 响应中的 retCode 字段为 SUCCESS，表示请求处理成功
                        // 可以继续处理其他业务逻辑
                        JSONObject jsonObject = new JSONObject(responseBody);
//                        String payOrderId = jsonObject.getString("payOrderId");
//                        JSONObject payParams = jsonObject.getJSONObject("payParams");
//                        String payUrl = payParams.getString("payUrl");
//                        return "支付订单号：" + payOrderId + "\n支付地址：" + payUrl;
                        return jsonObject.toString();
                    } else {
                        // 响应中的 retCode 字段不为 SUCCESS，表示请求处理失败
                        // 可以根据具体情况处理失败逻辑
                        if (responseBody.contains("\"retMsg\":\"签名失败\"")) {
                            // 签名失败
                            return  "签名失败";
                        } else if (responseBody.contains("\"retMsg\":\"参数格式校验错误\"")) {
                            // 参数格式校验错误
                            return  "参数格式校验错误";
                        } else {
                            // 其他错误
                            ObjectMapper objectMapper = new ObjectMapper();
                            Map<String, Object> data = objectMapper.readValue(responseBody, Map.class);
                            return (String) data.get("errDes") +(String) data.get("retMsg"); // 返回错误信息，例如："订单不存在" 或 "订单已支付" 等。
                        }
                    }
                } else {
                    // HTTP 请求失败
                    return "HTTP 请求失败，状态码："+statusCode;
                }
            } finally {
                // 关闭响应
                response.close();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    void setCriteria(PayInterfaceExample.Criteria criteria, PayInterface obj) {
        if(obj != null) {
            if(obj.getIfTypeCode() != null) criteria.andIfTypeCodeEqualTo(obj.getIfTypeCode());
            if(obj.getStatus() != null && obj.getStatus().byteValue() != -99) criteria.andStatusEqualTo(obj.getStatus());
        }
    }
}
